#pragma once
#include <string>
#include <vector>
#include <assert.h>
#include "../glm/glm.hpp"
#include "../glm/gtc/quaternion.hpp"

class _MD5Animation
{
public:
    _MD5Animation();
    ~_MD5Animation();
	
    // Load an animation from the animation file
    bool load(const char* filename);
    // Update this animation's joint set.
    void update(float fDeltaTime);
    // Draw the animated skeleton
    void draw();
	
    // The JointInfo stores the information necessary to build the
    // skeletons for each frame
    struct JointInfo{
        std::string	name;
        int         parentID;
        int         flags;
        int         startIndex;
    };
    typedef std::vector<JointInfo> JointInfoList;
	
    struct Bound{
        glm::vec3   min;
        glm::vec3   max;
    };
    typedef std::vector<Bound> BoundList;
	
    struct BaseFrame{
        glm::vec3   pos;
        glm::quat   orient;
    };
    typedef std::vector<BaseFrame> BaseFrameList;
	
    struct FrameData{
        int iFrameID;
        std::vector<float> frameData;
    };
    typedef std::vector<FrameData> FrameDataList;
	
    // A Skeleton joint is a joint of the skeleton per frame
    struct SkeletonJoint{
        SkeletonJoint()
		: parent(-1)
		, pos(0)
        {}
		
        SkeletonJoint( const BaseFrame& copy )
		: pos( copy.pos )
		, orient( copy.orient )
        {}
		
        int         parent;
        glm::vec3	pos;
        glm::quat   orient;
    };
    typedef std::vector<SkeletonJoint> SkeletonJointList;
	
    // A frame skeleton stores the joints of the skeleton for a single frame.
    struct FrameSkeleton{
        SkeletonJointList   joints;
    };
    typedef std::vector<FrameSkeleton> FrameSkeletonList;
	
    const FrameSkeleton& getSkeleton() const
    {
        return animatedSkeleton;
    }
	
    int getNumJoints() const
    {
        return iNumJoints;
    }
	
    const JointInfo& getJointInfo( unsigned int index ) const
    {
        assert( index < jointInfos.size() );
        return jointInfos[index];
    }
	
protected:
	
    JointInfoList       jointInfos;
    BoundList           bounds;
    BaseFrameList       baseFrames;
    FrameDataList       frames;
    FrameSkeletonList   skeletons;    // All the skeletons for all the frames
	
    FrameSkeleton       animatedSkeleton;
	
    // Build the frame skeleton for a particular frame
    void buildFrameSkeleton(FrameSkeletonList& skeletons,
							const JointInfoList& jointInfo,
							const BaseFrameList& baseFrames,
							const FrameData& frameData);
    void interpolateSkeletons(FrameSkeleton& finalSkeleton,
							  const FrameSkeleton& skeleton0,
							  const FrameSkeleton& skeleton1,
							  float fInterpolate);
	
private:
    int iMD5Version;
    int iNumFrames;
    int iNumJoints;
    int iFramRate;
    int iNumAnimatedComponents;
	
    float fAnimDuration;
    float fFrameDuration;
    float fAnimTime;
	
	int getFileLength(std::istream &file);
	void removeQuotes(std::string &str);
	void computeQuatW(glm::quat& quat);
};